package top.zhangjianyong.blog.utils;

import com.maxmind.geoip2.DatabaseReader;
import com.maxmind.geoip2.model.AsnResponse;
import com.maxmind.geoip2.model.CityResponse;
import java.net.InetAddress;
import lombok.extern.slf4j.Slf4j;
import top.zhangjianyong.blog.record.GeoIP2Info;

/** GeoIP2 查询工具类，基于MaxMind mmdb数据库，使用连接池管理器管理DatabaseReader实例 */
@Slf4j
public class GeoIP2Util {
    
    // 连接池管理器实例
    private static final GeoIP2PoolManager poolManager = GeoIP2PoolManager.getInstance();

    /**
     * 查询IP的所有归属地信息，返回GeoIP2Info对象
     *
     * @param ip IP地址
     * @return GeoIP2Info，查询失败时各字段为null
     */
    public static GeoIP2Info getIpInfo(String ip) {
        // 获取ASN信息
        var asnInfo = getAsnInfo(ip);

        // 获取地理位置信息
        var locationInfo = getLocationInfo(ip);

        // 获取IP版本信息
        String ipVersion = getIpVersion(ip);

        return new GeoIP2Info(
            ip,
            asnInfo.asn(),
            asnInfo.organization(),
            locationInfo.country(),
            locationInfo.subdivision(),
            locationInfo.city(),
            locationInfo.latitude(),
            locationInfo.longitude(),
            locationInfo.timeZone(),
            ipVersion);
    }

    /** 获取IP的ASN信息 通过GeoLite2-ASN.mmdb数据库查询： - ASN号：自治系统编号，用于标识网络运营商 - 组织名称：网络运营商或组织的名称 */
    private record AsnInfo(Long asn, String organization) {
    }

    private static AsnInfo getAsnInfo(String ip) {
        DatabaseReader asnReader = null;
        try {
            asnReader = poolManager.getAsnReader();
            if (asnReader == null) {
                log.warn("无法获取ASN DatabaseReader，跳过ASN信息查询");
                return new AsnInfo(null, null);
            }
            
            InetAddress ipAddress = InetAddress.getByName(ip);
            AsnResponse asnResponse = asnReader.asn(ipAddress);
            return new AsnInfo(
                asnResponse.getAutonomousSystemNumber(), asnResponse.getAutonomousSystemOrganization());
        } catch (Exception e) {
            log.error("获取ASN信息失败: {}", ip, e);
            return new AsnInfo(null, null);
        } finally {
            poolManager.returnAsnReader(asnReader);
        }
    }

    /**
     * 获取IP的地理位置信息 通过GeoLite2-City.mmdb数据库查询： - 国家：IP所属国家（优先返回中文名称） - 省份/州：IP所属省份或州（优先返回中文名称） -
     * 城市：IP所属城市（优先返回中文名称） - 纬度：地理位置纬度坐标 - 经度：地理位置经度坐标 - 时区：当地时区信息
     */
    private record LocationInfo(
        String country,
        String subdivision,
        String city,
        Double latitude,
        Double longitude,
        String timeZone) {
    }

    private static LocationInfo getLocationInfo(String ip) {
        DatabaseReader cityDbReader = null;
        try {
            cityDbReader = poolManager.getCityReader();
            if (cityDbReader == null) {
                log.warn("无法获取City DatabaseReader，跳过地理位置信息查询");
                return new LocationInfo(null, null, null, null, null, null);
            }
            
            InetAddress ipAddress = InetAddress.getByName(ip);
            CityResponse cityResponse = cityDbReader.city(ipAddress);

            String country = null;
            String subdivision = null;
            String city = null;
            Double latitude = null;
            Double longitude = null;
            String timeZone = null;

            if (cityResponse.getCountry() != null) {
                country =
                    cityResponse.getCountry().getNames().get("zh-CN") != null
                        ? cityResponse.getCountry().getNames().get("zh-CN")
                        : cityResponse.getCountry().getName();
            }
            if (!cityResponse.getSubdivisions().isEmpty()) {
                subdivision =
                    cityResponse.getSubdivisions().get(0).getNames().get("zh-CN") != null
                        ? cityResponse.getSubdivisions().get(0).getNames().get("zh-CN")
                        : cityResponse.getSubdivisions().get(0).getName();
            }
            if (cityResponse.getCity() != null) {
                city =
                    cityResponse.getCity().getNames().get("zh-CN") != null
                        ? cityResponse.getCity().getNames().get("zh-CN")
                        : cityResponse.getCity().getName();
            }
            if (cityResponse.getLocation() != null) {
                latitude = cityResponse.getLocation().getLatitude();
                longitude = cityResponse.getLocation().getLongitude();
                timeZone = cityResponse.getLocation().getTimeZone();
            }

            return new LocationInfo(country, subdivision, city, latitude, longitude, timeZone);
        } catch (Exception e) {
            log.error("获取地理位置信息失败: {}", ip, e);
            return new LocationInfo(null, null, null, null, null, null);
        } finally {
            poolManager.returnCityReader(cityDbReader);
        }
    }

    /** 获取IP版本信息 通过Java InetAddress判断IP类型： - IPv4：32位地址，如192.168.1.1 - IPv6：128位地址，如2001:db8::1 */
    private static String getIpVersion(String ip) {
        try {
            InetAddress ipAddress = InetAddress.getByName(ip);
            return ipAddress instanceof java.net.Inet6Address ? "IPv6" : "IPv4";
        } catch (Exception e) {
            log.error("获取IP版本信息失败: {}", ip, e);
            return null;
        }
    }

    /**
     * 获取连接池管理器状态信息
     */
    public static String getPoolStatus() {
        return poolManager.getManagerStatus();
    }

    /**
     * 获取ASN连接池状态
     */
    public static String getAsnPoolStatus() {
        return poolManager.getAsnPoolStatus();
    }

    /**
     * 获取City连接池状态
     */
    public static String getCityPoolStatus() {
        return poolManager.getCityPoolStatus();
    }

    /**
     * 获取当前内存使用情况（用于监控）
     */
    public static String getMemoryInfo() {
        Runtime runtime = Runtime.getRuntime();
        long totalMemory = runtime.totalMemory();
        long freeMemory = runtime.freeMemory();
        long usedMemory = totalMemory - freeMemory;
        long maxMemory = runtime.maxMemory();
        
        return String.format("Memory: %dMB/%dMB (%.1f%%)", 
            usedMemory / 1024 / 1024, 
            maxMemory / 1024 / 1024,
            (double) usedMemory / maxMemory * 100);
    }

    /**
     * 关闭连接池管理器，释放所有资源
     * 通常在应用关闭时调用
     */
    public static void shutdown() {
        poolManager.shutdown();
    }

    public static void main(String[] args) {
        System.out.println(getIpInfo("39.184.30.222"));
        System.out.println("连接池状态: " + getPoolStatus());
        System.out.println("内存使用: " + getMemoryInfo());
    }
}
